dd.textile.editor({
    init:function()
    {
        dd.control("textile.editor", function(o)
        {
            o = o || {};
            o.width = o.width || 500;
            o.height = o.height || 200;
            this.div = dd(this.parent).addElement("div");
            dd(this.div).css({
                "width":o.width + "px",
                "height":o.height + "px",
                "overflow":"hidden",
                "border":"2px solid #000",
                "cursor":"text",
                "lineHeight":"0"
            });
            this.textarea = dd(this.div).addElement("textarea");
            dd(this.textarea).css({
                "fontFamily":"Consolas",
                "fontSize":"13px",
                "margin":"0",
                "border":"none",
                "width":"20px",
                "height":"32px",
                "position":"relative",
                "top":"0",
                "left":"0"
            });
            this.svg = dd(this.div).addElement({"svg":"svg"});
            dd(this.svg).css({"position":"relative","top":"-32px", "left":"0"});
            // Add Cusor / Selection Group
            this.selectionGroup = dd(this.svg).addElement({"svg":"g"});
            this.textGroup = dd(this.svg).addElement({"svg":"g"});
            this.cursor = dd(this.svg).addElement({"svg":"rect"}, {
                style:"fill:#000",
                x:41,
                y:5,
                width:1,
                height:16
            });
            // Textarea Typing
            dd(this.textarea).event({
                keydown:function()
                {
                    var k = {
                        48:"0",
                        49:"1",
                        50:"2",
                        51:"3",
                        52:"4",
                        53:"5",
                        54:"6",
                        55:"7",
                        56:"8",
                        57:"9",
                        32:" ",
                        190:"."
                    };
                    // left = 37, up = 38, right = 39, down = 40
                    switch(this.key.code)
                    {
                        case 16:
                        case 17:
                        case 18:
                            break;
                        case 37:
                            dd(this.control).cursorX--;
                            break;
                        case 39:
                            dd(this.control).cursorX++;
                            break;
                        case 38:
                            dd(this.control).cursorY--;
                            break;
                        case 40:
                            dd(this.control).cursorY++;
                            break;
                        case 8:
                            var x = dd(this.control).cursorX;
                            var y = dd(this.control).cursorY;
                            var s = dd(this.control).start;
                            
                            if(x == 0)
                            {
                                dd(this.control).cursorY--;
                                dd(this.control).cursorX = dd(this.control).lines[y].length;
                                dd(this.control).text = dd(this.control).text.slice(0, s - 1)
                                                    + dd(this.control).text.slice(s);
                            }
                            else
                            {
                                dd(this.control).text = dd(this.control).text.slice(0, s - 1)
                                                    + dd(this.control).text.slice(s);
                                dd(this.control).cursorX--;
                            }
                            break;
                        case 13:
                            dd(this.control).text = dd.splice(
                                dd(this.control).text,
                                dd(this.control).start,
                                "\n"
                            );
                            dd(this.control).cursorY++;
                            dd(this.control).cursorX = 0;
                            break;
                        default:
                            dd(this.control).text = dd.splice(
                                dd(this.control).text,
                                dd(this.control).start,
                                this.key.code > 64 && this.key.code < 91
                                ? this.key.shift
                                    ? this.key.character
                                    : this.key.character.toLowerCase()
                                : k[this.key.code]
                            );
                            dd(this.control).cursorX++;
                    }
                    return false;
                },
                keyup:function()
                {
                    
                }
            }, {control:this});
            dd(this.svg).event({
                click:function()
                {
                    if(!dd(this.control).hasFocus)
                    {
                        dd(this.textarea).focus();
                    }
                    dd(this.control).hasFocus = true;
                    dd(this.control).trigger("focus");
                },
                mousedown:function()
                {
                    var x = Math.round((this.mouse.x - 32) / 7.3);
                    var y = Math.round((this.mouse.y + 4) / 16) - 1;
                    dd(this.control).cursorY = y;
                    dd(this.control).cursorX = x;
                },
                mouseup:function()
                {
                    var x = Math.round((this.mouse.x - 32) / 7.3);
                    var y = Math.round((this.mouse.y + 4) / 16) - 1;
                    y = y < 0 ? 0 : y;
                },
                mousemove:function()
                {
                    // Recode to save cursor setting
                    if(this.mouse.x <= 30 && this.div.self.e.style.cursor != "default")
                    {
                        dd(this.div).css({"cursor":"default"});
                    }
                    else if(this.mouse.x > 30  && this.div.self.e.style.cursor != "text")
                    {
                        dd(this.div).css({"cursor":"text"});
                    }
                }
            }, {control:this, div:this.div, textarea:this.textarea});
            dd(this.textarea).event({
                blur:function()
                {
                    dd(this.control).hasFocus = false;
                    
                    dd(this.control).trigger("blur");
                }
            }, {control:this});
            /*setInterval((function(c){
                return function()
                {
                    if(c.self.e.style.display == "none")
                    {
                        dd(c).css({"display":"inline"});
                    }
                    else
                    {
                        dd(c).css({"display":"none"});
                    }
                }
            })(this.c), 600);*/
            this.extend({
                hasFocus:false,
                get start()
                {
                    var x = this.cursorPosition.x;
                    var y = this.cursorPosition.y;
                    return this.lines[y].offset + x;
                },
                set start(v)
                {
                    
                },
                cursorPosition:{
                    x:0,
                    y:0
                },
                get cursorX()
                {
                    return this.cursorPosition.x;
                },
                set cursorX(x)
                {
                    var y = this.cursorPosition.y;
                    x = x < 0
                        ? 0
                        : x > this.lines[y].length
                            ? this.lines[y].length
                            : x;
                    this.cursorPosition.x = x;
                    dd(this.cursor).setAttribute({
                        "x":Math.round(x * 7.15) + 34
                    });
                    return x;
                },
                get cursorY()
                {
                    return this.cursorPosition.y;
                },
                set cursorY(y)
                {
                    y = y < 0
                        ? 0
                        : y >= this.lines.length
                            ? this.lines.length - 1
                            : y;
                    this.cursorPosition.y = y;
                    dd(this.cursor).setAttribute({
                        "y":(y * 16) + 5
                    });
                    return y;
                },
                _text:"",
                get text()
                {
                    return this._text;
                },
                set text(text)
                {
                    this._text = text;
                    dd(this).render();
                    return this._text;
                },
                lines:[],
                render:function()
                {
                    dd(this.textGroup).empty();
                    var formatFont = "font-size:13px;font-family:Consolas;";
                    var formatNormal = "fill:#000000;" + formatFont;
                    var formatTag = "fill:#000099;" + formatFont;
                    var formatLineNumbers = "fill:#FFFFFF;text-anchor:end;" + formatFont;
                    var characterWidth = 7.15;
                    var characterHeight = 16;
                    this.lines.splice(0, this.lines.length);
                    var lineMargin = 30;
                    var linesText = this.text.split(/\r?\n/);
                    // Line Numbers
                    dd(this.textGroup).addElement({"svg":"rect"}, {
                        style:"fill:#222222",
                        x:0,
                        y:0,
                        width:lineMargin,
                        height:o.height
                    });
                    dd(this.textGroup).addElement({"svg":"rect"}, {
                        style:"fill:#999",
                        x:lineMargin - 2,
                        y:0,
                        width:1,
                        height:o.height
                    });
                    var lineStart = 17;
                    var charCount = 0;
                    var charOffset = 0;
                    for(var y = 0; y < linesText.length; y++)
                    {
                        var words = linesText[y].split(/( )/g);
                        var start = lineMargin + 4;
                        var text = dd(this.textGroup).addElement({"svg":"text"}, y + 1, {
                            style:formatLineNumbers,
                            x:lineMargin - 6,
                            y:lineStart
                        });
                        if(words[0] != "")
                        {
                            // Not Empty Line
                            var nw = [];
                            for(var w = 0; w < words.length; w++)
                            {
                                if(start + (words[w].length * characterWidth) > o.width)
                                {
                                    this.lines.push({
                                        y:lineStart,
                                        length:charCount,
                                        offset:charOffset,
                                        groups:nw.slice(0)
                                    });
                                    start = lineMargin + 4;
                                    nw = [];
                                    lineStart += characterHeight;
                                    charOffset += charCount;
                                    charCount = 0;
                                }
                                charCount += words[w].length;
                                nw.push(words[w]);
                                if(w == words.length - 1)
                                {
                                    this.lines.push({
                                        y:lineStart,
                                        length:charCount,
                                        offset:charOffset,
                                        groups:nw.slice(0)
                                    });
                                    start = lineMargin + 4;
                                    nw = [];
                                    lineStart += characterHeight;
                                    charOffset += charCount;
                                    charCount = 0;
                                }
                                start += words[w].length * characterWidth;
                            }
                        }
                        else
                        {
                            // Empty Line
                            this.lines.push({
                                y:lineStart,
                                length:0,
                                offset:charOffset,
                                groups:[]
                            });
                            lineStart += characterHeight;
                        }
                        charOffset++;
                    }
                    // Code
                    var contentStart = lineMargin + 4;
                    for(var y = 0; y < this.lines.length; y++)
                    {
                        for(var x = 0; x < this.lines[y].groups.length; x++)
                        {
                            var format = formatNormal;
                            switch(this.lines[y].groups[x])
                            {
                                case "h1.":
                                case "p.":
                                    format = formatTag;
                                    break;
                                default:
                            }
                            var text = dd(this.textGroup).addElement({"svg":"text"}, this.lines[y].groups[x], {
                                style:format,
                                x:contentStart,
                                y:this.lines[y].y
                            });
                            contentStart += this.lines[y].groups[x].length * characterWidth;
                        }
                        contentStart = lineMargin + 4;
                        lineStart += characterHeight;
                    }
                }
            });
            dd(this).render();
        });
    }
});